package com.dominator.utils.encode;

import com.dominator.enums.ReqEnums;
import com.dominator.utils.exception.ApiException;
import com.dominator.utils.system.PropertiesLoader;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class MerchantAESUtil {


    public static PropertiesLoader propertiesLoader = new PropertiesLoader("sysconfig.properties");


    private static String KEY_ALGORITHM = "AES";
    private static String RANDOM_ALGORITHM = "SHA1PRNG";
    private static String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
    private static String CHARSET_NAME = "UTF-8";
    private static MerchantAESUtil instance = null;
    private Cipher encryptCipher = null;
    private Cipher decryptCipher = null;
    // TODO 加密KEY(我方提供并定期更换)
    public static String sKey = propertiesLoader.getProperty("merchant_key"); //开发时用



    static {
        // 初始化加密对象
        MerchantAESUtil.getInstance();
    }

    private MerchantAESUtil(String key) {
        // 初始化加密对象
        try {
            initCipher(sKey);
        } catch (Exception e) {
            System.out.println("加密对象初始化失败！");
            e.printStackTrace();
        }
    }

    public static MerchantAESUtil getInstance() {
        if (instance == null) {
            instance = new MerchantAESUtil(sKey);
        }
        return instance;
    }

    /**
     * 初始化加解密对象
     *
     * @param key
     * @throws Exception
     */
    private void initCipher(String key) throws ApiException {
        KeyGenerator kgen = null;
        try {
            kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);

        }
        SecureRandom random = null;
        try {
            random = SecureRandom.getInstance(RANDOM_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);

        }
        random.setSeed(key.getBytes());
        kgen.init(128, random);
        SecretKeySpec skeySpec = new SecretKeySpec(kgen.generateKey().getEncoded(), KEY_ALGORITHM);
        try {
            encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);

        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);

        }
        try {
            encryptCipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);

        }
        try {
            decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);

        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);

        }
        try {
            decryptCipher.init(Cipher.DECRYPT_MODE, skeySpec);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);

        }
    }

    /**
     * 加密
     * @param sSrc 报文
     * @return
     * @throws Exception
     */
    public String encrypt(String sSrc) throws ApiException {
        byte[] encrypted = new byte[0];
        String encrypt =null;
        try {
            encrypted = encryptCipher.doFinal(sSrc.getBytes(CHARSET_NAME));
            encrypt=Hex.encodeHexString(encrypted);
        } catch (Exception e){
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);
        }
        return encrypt.toUpperCase();
    }

    /**
     * 解密
     * @param sSrc 报文
     * @return
     * @throws Exception
     */
    public String decrypt(String sSrc) throws ApiException {
        byte[] encrypted = new byte[0];
        String originalString =null;
        try{
            char[] array = sSrc.toCharArray();
            encrypted = Hex.decodeHex(array);
            byte[] original = decryptCipher.doFinal(encrypted);
            originalString = new String(original, CHARSET_NAME);
        }catch (Exception e){
            throw new ApiException(ReqEnums.MERCHANT_VERIFY_ERROR);
        }
        return originalString;
    }

    public static void main(String[] args) {
        //商户加密
        String merchantId="12345678"; //商户号
        String secret="11223456"; //商户密钥
        long timestamp=System.currentTimeMillis(); //时间戳
        String merchantToken=MerchantAESUtil.getInstance().encrypt(merchantId+"_"+secret+"_"+timestamp);
        //时间戳必须在调用接口的前30分钟生成，超过时间会造成签名失败
        System.out.println(merchantToken);
    }


}
